import java.util.Arrays;
import java.util.LinkedList;
import java.util.ListIterator;


public class EventsContainer {

	private TimeGenerator goodGenerator;
	private TimeGenerator badGenerator;
	private LinkedList<Event> events = new LinkedList<Event>();
	
	public EventsContainer(Node[] nodes, TimeGenerator goodGenerator, TimeGenerator badGenerator) {
		this.goodGenerator = goodGenerator;
		this.badGenerator = badGenerator;
		
		generateFirstEvents(nodes);
	}
	
	
	
	private void generateFirstEvents(Node[] allNodes) {
		//generate events for every node, order the events by appearance order, save the increments between
		double[] times = new double[allNodes.length];
		for(int i = 0; i < times.length; ++i) {
			times[i] = goodGenerator.generateDouble();
		}
		Arrays.sort(times);
		//successive events
		Event e = new Event(times[0],times[0], allNodes[0], State.Bad);
		allNodes[0].reset();
		events.addLast(e);
		
		for(int i = 1; i < times.length; ++i) {
			Event e1 = new Event(times[i],times[i]- times[i-1], allNodes[i], State.Bad);
			events.addLast(e1);
			allNodes[i].reset();
		}

	}
	
	private Event generateNextEvent(Event ev) {
		double nextDuration;
		State nextState;
		
		if(ev.getState() == State.Bad) {
			nextDuration = badGenerator.generateDouble();
			nextState = State.Good;
		} else {
			nextDuration = goodGenerator.generateDouble();
			nextState = State.Bad;
		}
		
		return new Event(nextDuration, 0, ev.getNode(), nextState);
	}

	private void insertEvent(Event next) {
		double aggrTime = 0;
		double absDuration = next.getDuration();
		
		ListIterator<Event> iter = events.listIterator();
		
		Event ev = null;
		while(iter.hasNext()) {
			ev  = iter.next();
		
			if(aggrTime + ev.getRelDuration()  < absDuration ) {
				aggrTime= aggrTime + ev.getRelDuration();
			} else {
				next.setRelDuration(absDuration - aggrTime);
				iter.previous();
				iter.add(next);
				return;
			}
		}
		
		next.setRelDuration(absDuration - aggrTime);
		iter.add(next);
		
		return;
	}

	public void printEvents(LinkedList<Event> events) {
		
		for(Event e: events) {
			System.out.print("D: " +e.getRelDuration() + 
					", node at:" + 
					e.getNode().relIdx + 
					", St_f"+ e.getNode().state + 
					", St-t: " +e.getState() +
					".... ");
		}
		
		System.out.print("\n\n");
		
	}

	public Event pollEvent() {
		Event ev = events.pollFirst();
		Event next = generateNextEvent(ev);
		insertEvent(next);
		
		return ev;
	}

}
